package com.my.lucky.service;

import cn.hutool.core.collection.ListUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.my.lucky.config.IwencaiConfig;
import com.my.lucky.dto.GaiNianDTO;
import com.my.lucky.dto.SummaryBean;
import com.my.lucky.entity.*;
import com.my.lucky.model.ReviewInfo;
import com.my.lucky.model.Stock;
import com.my.lucky.repository.*;
import com.my.lucky.service.impl.StockServiceImpl;
import com.my.lucky.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StockDataLoader {
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    public static List<StockLimitUp> stocks10d = new ArrayList<>();
//    public static List<StockQueryRecord> now10Drecords = new ArrayList<>();
    //    public static List<Stock> all7Stock = new ArrayList<>();
    static Map<String, Double> stockMainList = new HashMap<>();
    // 创建本地缓存，设置1小时过期时间
    private final Cache<String, List<Stock>> stockCache = Caffeine.newBuilder()
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();
    LocalTime targetTime = LocalTime.of(14, 30);
    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private IWencaiServiceTools wencaiServiceTools;

    @Autowired
    private GaiNianInfoService gaiNianInfoService;

    @Autowired
    private GainianInfoRepository gainianInfoRepository;
    @Autowired
    private StockQueryRecordRepository stockQueryRecordRepository;
    @Autowired
    private StockLimitUpRepository stockLimitUpRepository;
    @Autowired
    private StockLimitUpService stockLimitUpService;

    @Autowired
    private StockLimitDownRepository downRepository;
    @Autowired
    private ReviewInfoService reviewInfoService;

    @Autowired
    private StockMainCostService mainCostService;

    @Autowired
    private IwencaiConfig iwencaiConfig;

    @Autowired
    private StockServiceImpl stockService;

    @Autowired
    private StockMonitorService monitorService;


    private static Map<String, List<Stock>> loadFromAPI(LocalDate startdate, LocalDate enddate, List<String> codes) throws IOException {
        Map<String, List<Stock>> stockMap = new HashMap<>();
        String dateStr = startdate.format(DATE_FORMATTER);
        String enddateStr = enddate.format(DATE_FORMATTER);
        System.out.printf("从API获取%s的数据...\n", dateStr);
        int total = codes.size();
        int processed = 0;

        for (String code : codes) {
            try {
                List<Stock> stocks = SohuStockAPI.getHistoryKLine(code, dateStr, enddateStr);
                if (stocks.size() == 0) {
                    log.info("code[{}] is 0", code);
                }
                // 这里只取今天的

                if (!stocks.isEmpty()) {
                    stockMap.put(code, stocks.subList(stocks.size() - 1, stocks.size()));
                }
                processed++;
                if (processed % 50 == 0 || processed == total) {
                    System.out.printf("已处理 %d/%d (%.2f%%)\n", processed, total, processed * 100.0 / total);
                }
            } catch (Exception e) {
                log.error("获取{}数据失败: {}", code, e.getMessage());
            }
        }

        return stockMap;
    }

    @Deprecated
    private static void mergeDailyData(Map<String, List<Stock>> allData, Map<String, List<Stock>> dailyData) {
        for (Map.Entry<String, List<Stock>> entry : dailyData.entrySet()) {
            String code = entry.getKey();
            List<Stock> dailyStocks = entry.getValue();

            allData.computeIfAbsent(code, k -> new ArrayList<>()).addAll(dailyStocks);
        }
    }

    @Deprecated
    private static List<String> initializeCodes() {
        List<String> codes = new ArrayList<>();

        // 上海主板：600000-601999, 603000-603999, 605000-605999
        for (int i = 600000; i <= 601999; i++) {
            codes.add(String.format("sh_%06d", i));
        }
        for (int i = 603000; i <= 603999; i++) {
            codes.add(String.format("sh_%06d", i));
        }
        for (int i = 605000; i <= 605999; i++) {
            codes.add(String.format("sh_%06d", i));
        }

        // 上海科创板：688000-688999
//        for (int i = 688000; i <= 688999; i++) {
//            codes.add(String.format("sh_%06d", i));
//        }

        // 深圳主板：000001-001999
        for (int i = 1; i <= 1999; i++) {
            codes.add(String.format("sz_%06d", i));
        }

        // 深圳创业板：300000-301999
        for (int i = 300000; i <= 301999; i++) {
            codes.add(String.format("sz_%06d", i));
        }

        // 深圳中小板：002000-004999
        for (int i = 2000; i <= 4999; i++) {
            codes.add(String.format("sz_%06d", i));
        }

        log.info("初始化股票代码列表，共 {} 个代码", codes.size());
        return codes;
    }

    /**
     * 盘前数据
     */
    @PostConstruct
    @Scheduled(cron = "0 23,38 9,14 ? * 1-5")
    void scheduleMain() {
        LocalDate endDatesearch = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT), 1).toLocalDate();
        Map<String, Double>  todayMap = mainCostService.getStockMainCostByDate(LocalDate.now());
        if (todayMap==null || todayMap.size()<5000) {
            stockMainList = wencaiServiceTools.searchStocksMaincost("主力持仓成本", false, endDatesearch);
            mainCostService.saveStockMainCostToDB(stockMainList, LocalDate.now());
//            log.info("stockMainList=" + endDatesearch + "=============" + stockMainList);
        }else{
//            log.info("getstockMainList from db=="+todayMap);
            stockMainList=todayMap;
        }
        dbschedule();
    }

    void dbschedule(){
        //===数据更新从数据库里面
        LocalDateTime endDate10d = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT), 15);//15天内的数据
        stocks10d = stockLimitUpService.getTodayLimitUpStocksBy(endDate10d, LocalDateTime.of(LocalDate.now(), LocalTime.MAX)); //10天涨停

        iwencaiConfig.setLimitstocks10d(stockLimitUpService.getTodayLimitUpStocksBy(endDate10d, LocalDateTime.of(LocalDate.now(), LocalTime.MIN)));

        LocalDateTime startDate1d = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(LocalDate.now(), LocalTime.MAX), 1);
        LocalDateTime startDate7d = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(LocalDate.now(), LocalTime.MAX), 7);
        List<Stock> all7Stock = stockRepository.findByTradeDateBetweenOrderByCodeAscTradeDateAsc(startDate7d.toLocalDate(), startDate1d.toLocalDate());//查询最近7天数据
        iwencaiConfig.setAll7Stock(all7Stock);

//        LocalDateTime startDates = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT), 10);
//        System.out.println("LocalDate.now().minusDays(1)=="+LocalDate.now().minusDays(1));
        List<StockQueryRecord> now10Drecords  = stockQueryRecordRepository.findByQueryTimeBetweenOrderByQueryTimeAsc(endDate10d, LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.MAX));//前一天查询的10天查询出来的
        iwencaiConfig.setNow10Drecords(now10Drecords);
        List<StockQueryRecord> nowtodayDrecords  = stockQueryRecordRepository.findByQueryTimeBetweenOrderByQueryTimeAsc(LocalDateTime.of(LocalDate.now(), LocalTime.MIN), LocalDateTime.of(LocalDate.now(), LocalTime.MAX));//今天的查询数据
        iwencaiConfig.setNowTodayDrecords(nowtodayDrecords);
    }
    /**
     * 盘中概念 个股数据
     */
//    @PostConstruct
    @Scheduled(cron = "0 8,28,38,58 9,10,11,13,14,16 ? * 1-5")
    void schedule() {
        List<GaiNianInfo> gaiNianInfoList = wencaiServiceTools.searchAllGainian("所有指数板块,资金,市值,涨幅,板块热度排名,昨天板块热度排名,最新boll中轨值,最新lower值,最新upper值,最新30分钟boll中轨值,最新30分钟lower值,最新30分钟upper值");
//            System.out.println(gaiNianInfoList);
        if (!gaiNianInfoList.isEmpty() && gaiNianInfoList.size() > 0) {
            gainianInfoRepository.deleteByCreateTimeAfterToday();
            gainianInfoRepository.saveAll(gaiNianInfoList);
            log.info("schedule 成功保存 {} 只指数数据", gaiNianInfoList.size());
        }

        List<Stock> stockList = wencaiServiceTools.searchAllStocks("个股涨幅,昨天收盘价格,热度排行榜,昨天热度排行排名,所属概念,资金流向,主力资金流向,所属行业,换手率,成交量,RSI1值,RSI2值,RSI3值,boll中轨值,lower值,upper值,OBV值,MAOBV值,开盘价,最低价,最高价,涨停价,跌停价,30分钟boll中轨值,30分钟lower值,30分钟upper值", false);
        log.info("schedule stockList 总数: {} schedule", stockList.size());
        if (stockMainList == null || stockMainList.size() <= 0) {
            scheduleMain();
        }
        if (stockList != null && stockList.size() > 0) {
            List<Stock> newstockList = new ArrayList<>();
            for (int i = 0; i < stockList.size(); i++) {
                Stock stock = stockList.get(i);
                if (stock != null) {
                    stock.setMainCost(stockMainList.get(stock.getCode()));
                    newstockList.add(stock);
                }
            }
            stockRepository.deleteByCreateTimeAfterToday();
            stockRepository.saveAll(newstockList);
            stockQueryRecordRepository.updateByQueryTimeAfterTodayFromStocksFlow();
            stockLimitUpRepository.updateByQueryTimeAfterTodayFromStocks();
            log.info("schedule 成功保存 {} 只全部股票数据", newstockList.size());
        }

        gaiNianInfoService.getSealOrderAmountSummary(LocalDateTime.now());

        String reviewGainian=checkGaiNian(gaiNianInfoList);//判断概念

        ReviewInfo reviewInfo = new ReviewInfo();
        reviewInfo.setReviewGainian(reviewGainian);
        GaiNianDTO gaiNianDTO = new GaiNianDTO();
        gaiNianDTO.setCreatedAt(LocalDateTime.now());
        reviewInfo.setReviewContent(gaiNianDTO.toReviewContent());
        reviewInfo.setReviewTime(LocalDate.now());
        reviewInfo.setUpdateTime(LocalDateTime.now());
        reviewInfoService.upsertByReview(reviewInfo);

        scheduleTodayReview();
        dbschedule();//更新数据库
    }
    /**
     * 盘中策略
     */
//    @PostConstruct
    // 周一到周五（1-5），9点和15点（9,15），每3分钟执行一次（0,3,6...57）
    @Scheduled(cron = "0 0/6 9,10,11,13,14 ? * 1-5")
    void scheduleCheck() {
        log.info("scheduleCheck==");
//        LocalDate endDate = LocalDate.now().minusDays(1);
        LocalDate endDate = LocalDate.now();
        LocalDate start = endDate.minusDays(40);

        Map<String, Stock> kdjStocks = wencaiServiceTools.searchKDJStocks("概念主力增仓上涨,日线KDJ向上,30分钟周期分时KDJ向上", false);
//        Map<String, Stock> kdjStocks = new HashMap<>();//

        String res="";
//        res+=stockService.checkAndDateRange(start, endDate, kdjStocks);// 30天主力进
//        res+=","+stockService.checkAndDateRangeWash(start, endDate, kdjStocks);// 30天主力进洗盘ing
//        res+=","+stockService.checkAndDateRangeRank(start, endDate, kdjStocks);// 当天前100

        res+=","+stockService.checkAndDateRangeBollFlow(start, endDate);// 关注的股票 Boll扩张
        res=stockService.checkAndDateRangeBoll20cm(start, endDate, kdjStocks);// Boll扩张 20厘米
        res+=","+stockService.checkAndDateRangeBoll10cm(start, endDate, kdjStocks);// Boll扩张 10厘米

        res+=","+stockService.checkAndDateRangeBoll(start, endDate, kdjStocks);// Boll扩张

        res+=","+stockService.checkAndDateRangeBollSearch(start, endDate);// 查询的股票 Boll扩张
//        res+=","+stockService.checkAndDateRangeBollLimit(start, endDate);// 10天涨停第二波

        stockService.checkAndDateRangeBollLimitOpen();// 涨停或者涨幅大于1%  15天内横盘的。。

        stockService.checkAndDateRangeBoll3D();// 历史连续3天复盘扩张的。。

        ReviewInfo reviewInfo = new ReviewInfo();
        reviewInfo.setReviewStock(res);
        reviewInfo.setReviewTime(LocalDate.now());
        reviewInfo.setUpdateTime(LocalDateTime.now());
        reviewInfoService.upsertByReview(reviewInfo);

        monitorService.monitor(iwencaiConfig.getFocus(), iwencaiConfig.getSearchKeyword());//条件查询
        checkGaiNian(null);
    }
    /**
     * 收盘补齐数据
     */
//    @PostConstruct
    @Scheduled(cron = "0 42 16 ? * 1-5")
    void scheduleGainian() {
        schedule();
        scheduleCheck();
    }
    /**
     * 17点20复盘 TODO
     */
//    @PostConstruct
    @Scheduled(cron = "0 50 16 ? * 1-5")
    void scheduleTodayReview(){
        todayReview(null);
        //板块如何找？ 板块月线 周线向上的。
        //个股如何找？ 盘中监控找
        log.info("要怎么复盘呢??头大的很!!!");
    }

    /**
     * 概念当天前200名，热度上升 TODO 获取概念Boll扩张
     * @return
     */
    public String checkGaiNian(List<GaiNianInfo> result) {
        String res = "";
        List<Map<String, Object>> maps = wencaiServiceTools.searchGainian(iwencaiConfig.getGainianKeyword());
        if (result != null && maps != null) {
            log.info("=checkGaiNian=" + result.size() +"===maps==="+maps.size());
//            log.info("=checkGaiNian maps=" + maps);
            Map<String, String> maps30 = new HashMap<>();
            for (int j = 0; j < maps.size(); j++) {
                Map<String, Object> value = maps.get(j); // 通过键获取值
                maps30.put(value.get("name").toString(), value.get("name").toString());
            }

            for (int j = 0; j < result.size(); j++) {
                GaiNianInfo summaryBean = result.get(j);
                if (summaryBean == null) {
                    continue; // 空列表直接返回
                }

                int index = 300;
                if (summaryBean != null
                        && summaryBean.getRankPosition() <= index
//                        && summaryBean.getChangePercent()>0
//                        && summaryBean.getSunstocksupratio()>50
                        && maps30.containsKey(summaryBean.getGainianName())
//                        && summaryBean.getDay1().compareTo(new BigDecimal(0))>0
//                        && summaryBean.getDay1().compareTo(summaryBean.getDay2now())>0
                ) {
                    List<Stock>  stocks = stockRepository.findByTradeDateBetweenAndCodeLikeOrderByConceptAscTradeDateDesc(LocalDate.now(), LocalDate.now(),summaryBean.getGainianName());
//                    System.out.println("checkGaiNian stocks==="+stocks);
                    if (stocks!=null && stocks.size()>0) {
                        res += summaryBean.getGainianName() + ",";
                    }
                }

            }
            res=handleElements(res,20);

            log.info("checkGaiNian res==" + res);
        }

        res+=gaiNianInfoService.gainiancheckAndDateRangeBoll();

//        System.out.println(result);
        return res;
    }

    /**
     * 复盘 TODO
     * @param now
     * @return
     */
    public GaiNianDTO todayReview(LocalDateTime now) {
        GaiNianDTO gaiNianDTO = new GaiNianDTO();
        if (now == null) {
            now = LocalDateTime.now();
        }
        List<SummaryBean> result = new ArrayList<>();

        log.info("todayReview=====1");

        String ReviewContent="";
        for (int i = 0; i < 1; i++) {

        LocalDate today = DateUtils.minusDaysExcludeWeekendAndYesterday(now, i).toLocalDate();
//        LocalDate today = now.toLocalDate();//today.minusDays(1);

        List<Stock> allStock = stockRepository.findByTradeDateBetweenOrderByCodeAscTradeDateAsc(today, today);
        if (allStock==null || allStock.size()==0){
            return gaiNianDTO;
        }
            System.out.println("today==="+i+"==============="+today+"===allStock=="+allStock.size());
        Map<String, Integer> sunstocks = new HashMap<>();
        Map<String, Integer> sunstocksUP = new HashMap<>();//上涨的家数
        Integer stocksUP = 0;//上涨的家数
        Integer stocksDown = 0;//下跌的家数
        Integer stocksLimit = 0;//涨停的家数
        Integer stockspin = 0;//平的家数
//       log.info("allStock==111=="+allStock.size());

        BigDecimal todayAll = new BigDecimal(0.0); //总资金
        BigDecimal todayAllMain = new BigDecimal(0.0); //总主力资金
        for (Stock stock : allStock) {
            todayAll = todayAll.add(stock.getCapitalFlow() != null ? stock.getCapitalFlow() : new BigDecimal(0.0));
            todayAllMain = todayAllMain.add(stock.getMainCapitalFlow() != null ? stock.getMainCapitalFlow() : new BigDecimal(0.0));
            if (stock.getChangePercent() != null && stock.getChangePercent() > 0) {
                stocksUP = stocksUP + 1;
            } else if (stock.getChangePercent() != null && stock.getChangePercent() < 0) {
                stocksDown = stocksDown + 1;
            } else {
                stockspin = stockspin + 1;
            }
            String concept = stock.getConcept();
            if (concept != null && !concept.isEmpty()) {// 按分号分割概念字符串
                String[] parts = concept.split(";");
                for (String part : parts) {
                    if (!part.trim().isEmpty()) {
                        sunstocks.put(part, sunstocks.get(part) == null ? 1 : sunstocks.get(part) + 1);
                        if (stock.getChangePercent() != null && stock.getChangePercent() > 0) {
                            sunstocksUP.put(part, sunstocksUP.get(part) == null ? 1 : sunstocksUP.get(part) + 1);
                        }
                    }
                }
            }
        }
        log.info("todayReview=====2");
        Map<String, Integer> sunstockslimit = new HashMap<>();//涨停数量
        List<StockLimitUp> stocks = stockLimitUpService.getTodayLimitUpStocksBy(LocalDateTime.of(today, LocalTime.MIDNIGHT), LocalDateTime.of(today, LocalTime.MAX));
        List<StockLimitDown> downstocks = downRepository.findTodayLimitUpStocksAndRecordTimeBetween(LocalDateTime.of(today, LocalTime.MIDNIGHT), LocalDateTime.of(today, LocalTime.MAX));

        for (StockLimitUp stock : stocks) {
            String concept = stock.getGainians();
            String limitUpReason = stock.getLimitUpReason();
            if (concept != null && !concept.isEmpty()) {// 按分号分割概念字符串
                // 优化后的代码
                String[] parts = {};
                String[] partsr = {};

                // 处理第一个字符串的分割，避免空指针和空字符串
                if (concept != null && !concept.isEmpty()) {
                    parts = concept.split(";");
                }

                // 处理第二个字符串的分割，注意split需要转义，同时避免空指针和空字符串
                if (limitUpReason != null && !limitUpReason.isEmpty()) {
                    partsr = limitUpReason.split("\\+"); // 这里需要用\\+转义，否则会报错
                }

                // 合并两个数组并去重
                Set<String> resultSet = new HashSet<>();
                // 添加第一个数组的元素
                resultSet.addAll(Arrays.asList(parts));
                // 添加第二个数组的元素（Set会自动去重）
                resultSet.addAll(Arrays.asList(partsr));

                // 转换为数组（如果需要）
                String[] finalResult = resultSet.toArray(new String[0]);
                for (String part : finalResult) {
                    if (!part.trim().isEmpty()) {
                        sunstockslimit.put(part, sunstockslimit.get(part) == null ? 1 : sunstockslimit.get(part) + 1);
                    }
                }
            }
            stocksLimit = stocks.size();
        }

        gaiNianDTO.setCreatedAt(LocalDateTime.of(today, LocalTime.MIN));
        gaiNianDTO.setStocksLimit(stocksLimit);
        gaiNianDTO.setStocksUP(stocksUP);
        gaiNianDTO.setStocksDown(stocksDown);
        gaiNianDTO.setStocksDownLimit(downstocks!=null?downstocks.size():0);
        gaiNianDTO.setStocksPin(stockspin);
        gaiNianDTO.setAllstocks(allStock.size());

//        List<GaiNianInfo> allEntities = repository.findByCreateTimeBetween(LocalDateTime.of(today, LocalTime.MIDNIGHT), LocalDateTime.of(today, LocalTime.MAX));//repository.findByCreateTime(LocalDateTime.of(today, LocalTime.MIDNIGHT));
//        log.info("todayReview==" + allEntities.size());
//        if (allEntities == null || allEntities.size() <= 0) {
//            return gaiNianDTO;
//        }
//        System.out.println("todayReview==222");
//        Map<String, BigDecimal> map20 = calculateSummaryForDays(now, 19);
//        Map<String, BigDecimal> map10 = calculateSummaryForDays(now, 9);
//        Map<String, BigDecimal> map7 = calculateSummaryForDays(now, 6);
//        Map<String, BigDecimal> map6 = calculateSummaryForDays(now, 5);
//        Map<String, BigDecimal> map5 = calculateSummaryForDays(now, 4);
//        Map<String, BigDecimal> map4 = calculateSummaryForDays(now, 3);
//        Map<String, BigDecimal> map3 = calculateSummaryForDays(now, 2);
//        Map<String, BigDecimal> map2 = calculateSummaryForDays(now, 1);
//        Map<String, BigDecimal> map1 = calculateSummaryForDays(now, 0);
//        // 获取所有不同的概念代码
//
//        // 为每个概念代码计算各时间段的汇总
//        LocalDateTime day2S = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(today, LocalTime.MIDNIGHT), 1);
//        LocalDateTime day2e = LocalDateTime.of(day2S.toLocalDate(), LocalTime.MAX);
//        List<GaiNianInfo> day2allEntities = repository.findByCreateTimeBetween(day2S, day2e);
//        Map<String, GaiNianInfo> day2all = new HashMap<>();
//        for (GaiNianInfo gaiNianInfo : day2allEntities) {
//            String gainianCode = gaiNianInfo.getGainianCode();
//            day2all.put(gainianCode, gaiNianInfo);
//        }
//
//        LocalDateTime day3S = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(today, LocalTime.MIDNIGHT), 2);
//        LocalDateTime day3e = LocalDateTime.of(day3S.toLocalDate(), LocalTime.MAX);
//        List<GaiNianInfo> day3allEntities = repository.findByCreateTimeBetween(day3S, day3e);
//        Map<String, GaiNianInfo> day3all = new HashMap<>();
//        for (GaiNianInfo gaiNianInfo : day3allEntities) {
//            String gainianCode = gaiNianInfo.getGainianCode();
//            day3all.put(gainianCode, gaiNianInfo);
//        }
//
//        LocalDateTime day5S = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(today, LocalTime.MIDNIGHT), 4);
//        LocalDateTime day5e = LocalDateTime.of(day5S.toLocalDate(), LocalTime.MAX);
//        List<GaiNianInfo> day5allEntities = repository.findByCreateTimeBetween(day5S, day5e);
//        Map<String, GaiNianInfo> day5all = new HashMap<>();
//        for (GaiNianInfo gaiNianInfo : day5allEntities) {
//            String gainianCode = gaiNianInfo.getGainianCode();
//            day5all.put(gainianCode, gaiNianInfo);
//        }
//
//        LocalDateTime day6S = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(today, LocalTime.MIDNIGHT), 5);
//        LocalDateTime day6e = LocalDateTime.of(day6S.toLocalDate(), LocalTime.MAX);
//        List<GaiNianInfo> day6allEntities = repository.findByCreateTimeBetween(day6S, day6e);
//        Map<String, GaiNianInfo> day6all = new HashMap<>();
//        for (GaiNianInfo gaiNianInfo : day6allEntities) {
//            String gainianCode = gaiNianInfo.getGainianCode();
//            day6all.put(gainianCode, gaiNianInfo);
//        }
//
//        LocalDateTime day7S = DateUtils.minusDaysExcludeWeekendAndYesterday(LocalDateTime.of(today, LocalTime.MIDNIGHT), 6);
//        LocalDateTime day7e = LocalDateTime.of(day7S.toLocalDate(), LocalTime.MAX);
//        List<GaiNianInfo> day7allEntities = repository.findByCreateTimeBetween(day7S, day7e);
//        Map<String, GaiNianInfo> day7all = new HashMap<>();
//        for (GaiNianInfo gaiNianInfo : day7allEntities) {
//            String gainianCode = gaiNianInfo.getGainianCode();
//            day7all.put(gainianCode, gaiNianInfo);
//        }
//
//        for (GaiNianInfo entity : allEntities) {
////            Map<String, Object> summary = new LinkedHashMap<>();
////            String code = entity.getGainianCode();
////
//            gaiNianDTO.setCreatedAt(entity.getCreateTime());
//            // 创建SummaryBean实例替代Map
//            SummaryBean summary = new SummaryBean();
//            String code = entity.getGainianCode();
//
//            // 设置创建时间（原gaiNianDTO的属性也转移到bean中）
//            summary.setCreatedAt(entity.getCreateTime());
//            summary.setGainianCode(code);
//
//            summary.setRankPosition(entity.getRankPosition());
//            summary.setOldRankPosition(entity.getOldRankPosition());
//
//            summary.setMarketValue(entity.getMarketValue());
//            summary.setChangePercent(entity.getChangePercent());
//            summary.setGainianName(entity.getGainianName());
//            summary.setGainianNamepy(PinyinUtils.getWordInitials(entity.getGainianName()));
//
//            // 计算各时间段的汇总，使用bean的setter替代map.put
//            summary.setDay2now(day2all.get(code) != null ? day2all.get(code).getSealOrderAmount() : new BigDecimal(0));
//            summary.setDay3now(day3all.get(code) != null ? day3all.get(code).getSealOrderAmount() : new BigDecimal(0));
//            // summary.setDay4now(day4all.get(code) != null ? day4all.get(code).getSealOrderAmount() : 0);
//            summary.setDay5now(day5all.get(code) != null ? day5all.get(code).getSealOrderAmount() : new BigDecimal(0));
//            summary.setDay6now(day6all.get(code) != null ? day6all.get(code).getSealOrderAmount() : new BigDecimal(0));
//            summary.setDay7now(day7all.get(code) != null ? day7all.get(code).getSealOrderAmount() : new BigDecimal(0));
//
//            summary.setDay20(map20.get(code));
//            summary.setDay10(map10.get(code));
//            summary.setDay7(map7.get(code));
//            summary.setDay6(map6.get(code));
//            summary.setDay5(map5.get(code));
//            summary.setDay4(map4.get(code));
//            summary.setDay3(map3.get(code));
//            summary.setDay2(map2.get(code));
//            summary.setDay1(map1.get(code));
//
//            Integer suns = sunstocks.get(entity.getGainianName());
//            if ((suns == null || suns == 0) && (allStock != null && allStock.size() > 0)) {
//                suns = 0;
//                continue;
//            }
//            summary.setSunstocks(suns);
//
//            Integer sunsup = sunstocksUP.get(entity.getGainianName());
//            if (sunsup == null || sunsup == 0) {
//                sunsup = 0;
//            }
//            summary.setSunstocksup(sunsup);
//
//            // 计算上涨比例
//            Double sunstocksupratio = (suns == 0 || suns==null)? 0.00 : (double) sunsup / suns;
//            summary.setSunstocksupratio(sunstocksupratio * 100);
//
//            Integer sunslimit = sunstockslimit.get(entity.getGainianName());
//            if (sunslimit == null || sunslimit == 0) {
//                sunslimit = 0;
//            }
//            summary.setSunstockslimit(sunslimit);
//
//            // 计算涨停比例
//            Double sunstockslimitratio = suns == 0 ? 0.00 : (double) sunslimit / suns;
//            summary.setSunstockslimitratio(sunstockslimitratio * 100);
//
//            result.add(summary);
//        }
//
        log.info("allStock==22222==" + result.size());
        gaiNianDTO.setResult(result);
        gaiNianDTO.setTodayAll(todayAll);
        gaiNianDTO.setTodayAllMain(todayAllMain);
            ReviewContent+=gaiNianDTO.toReviewContent()+"\n";
        }

        ReviewInfo reviewInfo = new ReviewInfo();
        reviewInfo.setReviewContent(ReviewContent);
        reviewInfo.setReviewTime(now.toLocalDate());
        reviewInfo.setUpdateTime(LocalDateTime.now());
        ReviewInfo checkGai = reviewInfoService.upsertByReviewTime(reviewInfo);

        if (checkGai!=null && checkGai.getReviewGainian()!=null && LocalDateTime.now().getHour()>=16){ //4点后执行
            String[] gnames = checkGai.getReviewGainian().split(",");
            String newGnames="";
            for (int i = 0; i < gnames.length; i++) {
                List<Stock>  stocks = stockRepository.findByTradeDateBetweenAndCodeLikeOrderByConceptAscTradeDateDesc(LocalDate.now(), LocalDate.now(),gnames[i]);
                if (stocks!=null && stocks.size()>0) {
                    newGnames += gnames[i] + ",";
                }
            }
//            System.out.println("newGnames=="+newGnames);
            checkGai.setReviewGainian(newGnames);
            reviewInfoService.upsertByReviewTime(checkGai);
        }
        log.info("allStock==reviewInfo==" + reviewInfo);
//        checkGaiNian(result);
        return gaiNianDTO;
    }

    /**
     * 处理逗号分隔的字符串，取前index个非空元素并重新拼接
     * @param testStr 逗号分隔的字符串（如"a,b,c,d"）
     * @param index 最大元素数量
     * @return 前index个非空元素的逗号拼接字符串
     */
    public String handleElements(String testStr, int index) {
        // 存储最多index个元素（只保留前面的）
        List<String> limitedElements = new ArrayList<>(index);

        // 处理空字符串或null的情况
        if (testStr == null || testStr.trim().isEmpty()) {
            return "";
        }
        // 将字符串按逗号拆分为数组
        String[] elements = testStr.split(",");

        if (elements.length<=index) {
            return testStr;
        }
        // 遍历拆分后的元素，取前index个非空元素
        for (String element : elements) {
            // 若已收集到足够数量，停止遍历
//            if (limitedElements.size() >= index) {
//                break;
//            }
            // 过滤空值或空白字符串（去除前后空格后判断）
            if (element != null && !element.trim().isEmpty()) {
                limitedElements.add(element.trim()); // 去除元素前后空格
            }
        }
        // 用逗号拼接收集到的元素
        String res = String.join(",", limitedElements);
        log.info("handleElements=="+res);
        return res;
    }


    /**
     * 将纯数字股票代码转换为API所需的格式
     * @param pureCode 纯数字股票代码
     * @return 带前缀的股票代码
     */
    private String toApiFormat(String pureCode) {
        return pureCode.startsWith("6") ? "sh_" + pureCode : "sz_" + pureCode;
    }

    /**
     * 将API格式的股票代码转换为纯数字格式
     *
     * @param apiCode API格式的股票代码
     * @return 纯数字股票代码
     */
    private String toPureCode(String apiCode) {
        if (apiCode.startsWith("sh_") || apiCode.startsWith("sz_") || apiCode.startsWith("cn_")) {
            return apiCode.substring(3);
        }
        return apiCode;
    }

    @Transactional
    public void loadStocksForCodes(LocalDate endDate, int DAYS_TO_LOAD, List<String> pureCodes) throws IOException {
        // 获取过去DAYS_TO_LOAD天的日期列表
        List<LocalDate> dates = new ArrayList<>();
        for (int i = 0; i < DAYS_TO_LOAD; i++) {
            dates.add(endDate.minusDays(i));
        }

        // 将股票代码转换为API所需的格式
        List<String> apiCodes = pureCodes.stream()
                .map(this::toApiFormat)
                .collect(Collectors.toList());

        List<List<String>> partition = ListUtil.partition(apiCodes, 200);

        for (List<String> strings : partition) {
            // 使用纯数字代码检查数据库
            String pureCode = toPureCode(strings.get(0));
            List<Stock> byCode = stockRepository.findByCodeAndTradeDateBetweenOrderByTradeDateAsc(
                    pureCode,
                    dates.get(0),
                    dates.get(0)
            );

            if (!byCode.isEmpty()) {
                log.info("dates存在数据: {} - {}", dates.get(0).format(DATE_FORMATTER), dates.get(dates.size() - 1));
                continue;
            }
            //   System.out.println("----------------");
            Map<String, Map<String, List<Stock>>> dateStockMap = new HashMap<>();
            Map<String, List<Stock>> stockData = loadFromAPI(dates.get(dates.size() - 1), dates.get(0), strings);

            // 按日期重新组织数据，同时转换股票代码为纯数字格式
            for (Map.Entry<String, List<Stock>> entry : stockData.entrySet()) {
                String pureStockCode = toPureCode(entry.getKey());
                for (Stock stock : entry.getValue()) {
                    // 设置纯数字代码
                    stock.setCode(pureStockCode);
                    dateStockMap.computeIfAbsent(stock.getDate().replaceAll("-", ""), k -> new HashMap<>())
                            .computeIfAbsent(pureStockCode, k -> new ArrayList<>())
                            .add(stock);
                }
            }
            //  System.out.println("----------------");
            // 遍历每一天
            for (LocalDate date : dates) {
                String dateStr = date.format(DATE_FORMATTER);
                String format = LocalDate.now().format(DATE_FORMATTER);
                if (format.equals(dateStr)) {
                    log.info("处理日期: {}", dateStr);
                    Map<String, List<Stock>> dailyData = dateStockMap.get(dateStr);
                    if (dailyData == null) {
                        continue;
                    }
                    for (List<Stock> stocks : dailyData.values()) {
                        stockRepository.saveAll(stocks);
                    }
                }
            }
        }
        // System.out.println("----------------------------------");
    }

    /**
     * 获取最近30个交易日的股票数据
     *
     * @return Map<String, List < Stock>> key为股票代码，value为该股票的历史数据列表
     */
    public Map<String, List<Stock>> getLast30DaysStockData(boolean gemOnly) {
        // 获取最近的30个交易日期
        List<LocalDate> tradeDates = stockRepository.findDistinctTradeDateOrderByTradeDateDesc()
                .stream()
                .limit(30)
                .collect(Collectors.toList());

        if (tradeDates.isEmpty()) {
            return new HashMap<>();
        }

        // 获取起止日期
        LocalDate startDate = tradeDates.get(tradeDates.size() - 1);
        LocalDate endDate = tradeDates.get(0);

        // 查询所有股票数据
        List<Stock> allStocks = gemOnly ?
                stockRepository.findByTradeDateBetweenAndCodeStartingWithOrderByCodeAscTradeDateAsc(startDate, endDate, "sz_300") :
                stockRepository.findByTradeDateBetweenOrderByCodeAscTradeDateAsc(startDate, endDate);

        // 按股票代码分组
        Map<String, List<Stock>> result = new HashMap<>();
        for (Stock stock : allStocks) {
            result.computeIfAbsent(stock.getCode(), k -> new ArrayList<>()).add(stock);
        }

        return result;
    }

    /**
     * 清理重复的股票数据，对于相同股票代码和日期的数据只保留一条
     */
    @Transactional
    public void cleanDuplicateStocks() {
        // 首先查找有哪些重复数据
        List<Object[]> duplicates = stockRepository.findDuplicateStocks();
        if (!duplicates.isEmpty()) {
            log.info("发现重复数据");
            for (Object[] duplicate : duplicates) {
                log.info("股票代码：{}, 日期：{}, 重复次数：{}",
                        duplicate[0], duplicate[1], duplicate[2]);
            }
            // 删除重复数据，每组只保留一条
            stockRepository.deleteDuplicateStocks();
            log.info("重复数据清理完成");
        } else {
            log.info("没有发现重复数据");
        }
    }

    /**
     * 获取指定股票的历史数据
     *
     * @param code 股票代码
     * @return 股票历史数据列表
     */
    public List<Stock> getStockHistory(String code) {
        // 首先尝试从缓存中获取数据
        List<Stock> cachedStocks = stockCache.getIfPresent(code);
        if (cachedStocks != null) {
            return cachedStocks;
        }

        // 缓存中没有，从数据库获取
        List<LocalDate> tradeDates = stockRepository.findDistinctTradeDateOrderByTradeDateDesc()
                .stream()
                .limit(30)
                .collect(Collectors.toList());

        if (tradeDates.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取起止日期
        LocalDate startDate = tradeDates.get(tradeDates.size() - 1);
        LocalDate endDate = tradeDates.get(0);

        // 查询指定股票的历史数据
        List<Stock> stocks = stockRepository.findByCodeAndTradeDateBetweenOrderByTradeDateAsc(code, startDate, endDate);

        // 将查询结果放入缓存
        stockCache.put(code, stocks);

        return stocks;
    }

} 